﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.IO;

namespace ApplicationGenerator.CommonModule
{
    /// <summary>
    /// Kompilator modeli
    /// </summary>
    public static class ModelsCompiler
    {
        /// <summary>
        /// Nazwa katalogu, w którym znajdują się dll'ki referowane przez kod
        /// </summary>
        private const string ReferencedDirectoryName = "ReferencedAssemblies";

        /// <summary>
        /// Nazwa pliku .cs, w którym znajdują się definicje modeli
        /// </summary>
        private const string CSharpFileNameExtension = "*.cs";

        /// <summary>
        /// Kompiluje modele do docelowej dll'ki
        /// </summary>
        /// <param name="sourceModelsPath">Katalog w którym znajduje się definicja modeli</param>
        /// <param name="destinationPath">Katalog docelowy, w którym ma zostać utworzone assembly z modelami</param>
        /// <returns>Rezultaty kompilacji</returns>
        public static CompilerResults Compile(string sourceModelsPath, string destinationPath)
        {
            if (sourceModelsPath == null)
            {
                throw new ArgumentNullException("directoryPath");
            }

            if (destinationPath == null)
            {
                throw new ArgumentNullException("destinationPath");
            }

            if (!Directory.Exists(sourceModelsPath))
            {
                throw new DirectoryNotFoundException(sourceModelsPath);
            }

            if (!Directory.Exists(destinationPath))
            {
                throw new DirectoryNotFoundException(sourceModelsPath);
            }

            Dictionary<string, string> compilerOptions = new Dictionary<string, string>();
            compilerOptions.Add("CompilerVersion", "v3.5");
            CSharpCodeProvider codeProvider = new CSharpCodeProvider(compilerOptions);

            if (Directory.GetFiles(sourceModelsPath, CSharpFileNameExtension, SearchOption.TopDirectoryOnly).Length == 0)
            {
                throw new FileNotFoundException("Nie znaleziono plików z definicjami modeli");
            }

            string referencedDirectoryPath = Path.Combine(sourceModelsPath, ReferencedDirectoryName);
            if (!Directory.Exists(referencedDirectoryPath))
            {
                throw new DirectoryNotFoundException(referencedDirectoryPath);
            }

            CompilerParameters parameters = new CompilerParameters();
            parameters.GenerateExecutable = false;
            parameters.OutputAssembly = Path.Combine(destinationPath, ActiveRecordConfiguration.AssemblyName);
            parameters.ReferencedAssemblies.AddRange(Directory.GetFiles(Path.Combine(sourceModelsPath, ReferencedDirectoryName)));

            return codeProvider.CompileAssemblyFromFile(
                parameters,
                Directory.GetFiles(sourceModelsPath, CSharpFileNameExtension, SearchOption.TopDirectoryOnly));
        }
    }
}
